/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package pl.mwas.proteana.math.factorials;

import java.math.BigDecimal;
import java.util.Objects;
import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author loskov
 */
public abstract class Factorial {
    
    public static Log logger = LogFactory.getLog("math.factorials.Factorial");
    protected BigDecimal base;
    protected BigDecimal result;
    
    public Factorial() {
        this.result = null;
    }
    public Factorial(int n) {
        this(new BigDecimal(n));
    }
    
    public Factorial(BigDecimal n) {
        isBaseValid(n);
        this.base = n;
        this.result = calculate();
    }

    private boolean isBaseValid(BigDecimal n) throws ArithmeticException {
        if (n == null) {
            logger.error("Factorial base cannot be null");
            throw new ArithmeticException("Cause: n = null @ n!");
        } else if (n.intValue() < 0) {
            logger.error("Factorial cannot be calculated for n < 0");
            throw new ArithmeticException("Cause: n < 0 @ n!");
        } else
            return true;
    }
    
    protected abstract BigDecimal calculate();
    
    public BigDecimal getResult() {
        return this.result;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 53 * hash + Objects.hashCode(this.result);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Factorial other = (Factorial) obj;
        if (!Objects.equals(this.result, other.result)) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return base + ":" + result;
    }
    
    
    
}
